home *** CD-ROM | disk | FTP | other *** search
/ Collection of Tools & Utilities / Collection of Tools and Utilities.iso / keyb / recall12.zip / INTPROTO.TXT < prev    next >
Text File  |  1991-11-09  |  21KB  |  511 lines

  1.  
  2.  
  3.  
  4.  
  5.  
  6.  
  7.                    IBM'S INTERRUPT-SHARING PROTOCOL
  8.                             by Chris Dunford
  9.                                  8/6/91
  10.  
  11. In the PS/2 BIOS Interface Technical Reference, IBM has suggested a
  12. protocol for the sharing of system interrupts.  Although the protocol
  13. was intended to allow sharing of hardware interrupts, it is equally
  14. usable for software interrupts.
  15.  
  16. One of the features of the interrupt sharing protocol is that it permits
  17. a resident program to "unhook" itself from an interrupt even if it is
  18. not the first interrupt handler in the chain of handlers.  The benefit
  19. of this should be immediately apparent to developers of TSRs.  It is a
  20. commonplace in TSR manuals to see verbiage along these lines:
  21.  
  22.     Program X can be unloaded from memory by typing ... at the DOS
  23.     prompt.  For this to work, however, X must be the last TSR loaded.
  24.     If other resident software is loaded after X, you cannot unload X.
  25.  
  26. The interrupt sharing protocol eliminates this restriction.
  27.  
  28. However, for the protocol to work, it must be followed by the majority
  29. of TSR writers.  To date, this has not occurred.  Because the protocol
  30. is easy to implement and inexpensive in terms of memory, I feel that at
  31. least part of the reason for this must be that the protocol has not been
  32. widely publicized; most DOS programmers are simply unaware of it.  I am
  33. offering this document as a modest attempt to let DOS programmers know
  34. that a solution exists for a longstanding problem.
  35.  
  36. Let me add as a caveat that I do not have and have not examined the
  37. primary source for this information--the PS/2 BIOS reference.  Most of
  38. the information in this paper was gleaned from other sources, augmented
  39. by my own experiences in writing TSRs.  The most recent writeup as of
  40. this date (August 6, 1991) was in the 7/91 issue of the Microsoft
  41. Systems Journal.
  42.  
  43. This document is not copyrighted.  Its distribution in any form is
  44. encouraged (please try to avoid making a profit on it).  If you make
  45. changes, please make sure they are clearly marked so that I get blame
  46. only for my own errors and credit only where it is due.  Please try to
  47. get any changes, amplifications, corrections, etc., back to me so that a
  48. clean copy can be redistributed if necessary.
  49.  
  50. The perpetrator of this document is:
  51.  
  52.     Chris Dunford
  53.     The Cove Software Group
  54.     PO Box 1072
  55.     Columbia, MD 21044
  56.     301/992-9371
  57.  
  58.     CompuServe: 76703,2002
  59.     Internet: 76703.2002@compuserve.com
  60.  
  61.  
  62. THE PROBLEM
  63. -----------
  64. The vast majority of terminate-and-stay-resident (TSR) programs need to
  65. intercept one or more hardware or software interrupts.  Shown below is
  66. typical code for accomplishing this, assuming that the interrupt to be
  67. "hooked" is the DOS service interrupt (INT 21h):
  68.  
  69.      (data)
  70.         OldInt21    dd ?
  71.  
  72.      (installation code)
  73.         ; Save current INT 21h vector
  74.         mov ax,3521h
  75.         int 21h
  76.         mov word ptr OldInt21,bx
  77.         mov word ptr OldInt21+2,es
  78.  
  79.         ; Set new INT 21h vector
  80.         mov dx,offset NewInt21
  81.         mov ax,2521h
  82.         int 21h
  83.         ...
  84.  
  85.     (interrupt handler)
  86.     NewInt21:
  87.         (perform processing as required)
  88.         jmp OldInt21
  89.  
  90. The installation code saves the current contents of the INT 21h vector
  91. in a 32-bit variable called OldInt21, which is known as a "downward
  92. link" or "downlink" because it provides a link "downward" in the chain
  93. of interrupt handlers.  The installation then sets the INT 21h vector to
  94. point to its own interrupt handler at NewInt21.  When an INT 21h call is
  95. subsequently issued, execution is routed to NewInt21, which performs
  96. whatever processing it needs to do.  It then executes a far jump to the
  97. address in OldInt21, allowing previously installed TSRs (and DOS, of
  98. course) to do their work.  The flow of control looks like this if only
  99. one TSR is loaded:
  100.  
  101.                             vector          OldInt21
  102.     application (int 21h) -----------> TSR ----------> DOS
  103.  
  104. To unload itself, the TSR simply resets the INT 21h vector to its
  105. initial contents (i.e., the address in OldInt21).  The TSR's interrupt
  106. handler is now no longer in the chain, and the TSR can be safely
  107. unloaded:
  108.  
  109.                             vector
  110.     application (int 21h) -----------> DOS
  111.  
  112. This scheme works fairly well until the situation arises where more than
  113. one program tries to hook the same vector:
  114.  
  115.           vector           OldInt21A        OldInt21B
  116.     app -----------> TSR A ---------> TSR B ---------> DOS
  117.  
  118. This also works fine--until TSR B wants to unload itself.  B cannot
  119. follow its normal procedure and replace the INT 21h vector with the
  120. contents of its OldInt21.  If it did, the interrupt chain would look
  121. like this:
  122.  
  123.           vector
  124.     app -----------> DOS
  125.  
  126. The problem, obviously, is that TSR A has been unceremoniously removed
  127. from the interrupt chain; it has been disabled without notice, even
  128. though it remains in memory.  This is obviously an unsatisfactory--and
  129. quite possibly dangerous--situation.
  130.  
  131. Nor can TSR B simply unload itself without fixing INT 21h.  TSR A would
  132. still have TSR B's address stored in its OldInt21; when it has completed
  133. its processing of an INT 21h call, it will jump to the address where TSR
  134. B was at one time--but is no longer--loaded.  The only unpredictable
  135. aspect of the result is which kind of reboot (hard or soft) will be
  136. required.
  137.  
  138. TSR B's only option is to wave its hands and notify the user that it
  139. cannot be unloaded.  This is satisfying to the programmer ("We told you
  140. that you can't do this") but not to the user.
  141.  
  142. The root of the problem is that TSR A has TSR B's address, but not vice
  143. versa.  If TSR B knew where TSR A was keeping its (B's) address, the
  144. resolution would be simple:  B could simply copy its downlink into A's
  145. downlink.
  146.  
  147. Here is a hypothetical memory map:
  148.  
  149.                 ---------------------
  150.                     VECTOR TABLE
  151.     0000:0084   INT21h vector = 1200:0240 --+
  152.                 ----------------------      |
  153.                                             |
  154.                 ----------------------      |
  155.                        TSR A                |
  156.     1200:0240   NewInt21 (int handler) <----+
  157.                         ...
  158.     1200:0642   OldInt21 = 1000:0296   ---+
  159.                 ----------------------    |
  160.                                           |
  161.                 ----------------------    |
  162.                        TSR B              |
  163.     1000:0296   NewInt21 (int handler) <--+
  164.                         ...
  165.     1000:0415   OldInt21 = 0070:1234   ---+
  166.                 ----------------------    |
  167.                                           |
  168.                 ----------------------    |
  169.                         DOS               |
  170.     0070:1234   INT 21h entry point    <--+
  171.                         ...
  172.                 ----------------------
  173.  
  174. The vector table entry for INT 21h points to TSR A's interrupt handler
  175. at 1200:0240.  TSR A's OldInt21 contains TSR B's interrupt handler
  176. address (1000:0296); when A has completed its work, it jumps to B at
  177. that address.  B has DOS's address (0070:1234) in its OldInt21; when it
  178. has finished, it jumps to DOS's address.
  179.  
  180. To take itself out of the chain, all B would have to do would be to put
  181. its downward link (DOS's address, contained in B's OldInt21) into A's
  182. downward link (which currently contains B's address):
  183.  
  184.                 ---------------------
  185.                     VECTOR TABLE
  186.     0000:0084   INT21h vector = 1200:0240 --+
  187.                 ----------------------      |
  188.                                             |
  189.                 ----------------------      |
  190.                        TSR A                |
  191.     1200:0240   NewInt21 (int handler) <----+
  192.                         ...
  193.     1200:0642   OldInt21 = 0070:1234   ---+     <=== change made here
  194.                 ----------------------    |
  195.                                           |
  196.                 ----------------------    |
  197.                        TSR B              |
  198.     1000:0296   NewInt21 (int handler)    |
  199.                         ...